/*
 * 爱组搭，低代码组件化开发平台
 * ------------------------------------------
 * 受知识产权保护，请勿删除版权申明，开发平台不允许做非法网站，后果自负
 */
package com.aizuda.boot.modules.system.service.impl;

import com.aizuda.boot.modules.business.permission.domain.entity.RoleDataIsolationEntity;
import com.aizuda.boot.modules.business.permission.domain.entity.RolePermissionEntity;
import com.aizuda.boot.modules.business.permission.domain.request.PageRoleVO;
import com.aizuda.boot.modules.business.permission.domain.response.PageRoleResponseVO;
import com.aizuda.boot.modules.common.constant.enums.PermissionStatusType;
import com.aizuda.boot.modules.common.constant.enums.ValidityType;
import com.aizuda.boot.modules.business.permission.mapper.RoleDataIsolationMapper;
import com.aizuda.boot.modules.business.permission.mapper.RolePermissionMapper;
import com.aizuda.boot.modules.system.entity.*;
import com.aizuda.boot.modules.system.entity.dto.RoleResourceDTO;
import com.aizuda.boot.modules.system.entity.dto.SysRoleDTO;
import com.aizuda.boot.modules.system.entity.dto.SysRoleDetailDTO;
import com.aizuda.boot.modules.system.mapper.*;
import com.aizuda.boot.modules.system.service.ISysRoleResourceService;
import com.aizuda.boot.modules.system.service.ISysRoleService;
import com.aizuda.boot.modules.system.service.ISysUserRoleService;
import com.aizuda.core.api.ApiAssert;
import com.aizuda.service.service.BaseServiceImpl;
import com.aizuda.service.vo.TreeVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.jsonwebtoken.lang.Collections;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统角色 服务实现类
 *
 * @author 青苗
 * @since 2021-11-03
 */
@Service
@AllArgsConstructor
public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {
    private ISysUserRoleService sysUserRoleService;
    private ISysRoleResourceService sysRoleResourceService;

    @Resource
    private SysRoleMapper sysRoleMapper;

    @Resource
    private RolePermissionMapper rolePermissionMapper;

    @Resource
    private RoleDataIsolationMapper roleDataIsolationMapper;

    @Resource
    private SysUserRoleMapper sysUserRoleMapper;

    @Resource
    private SysDepartmentMapper sysDepartmentMapper;

    @Resource
    private SysUserDepartmentMapper sysUserDepartmentMapper;

    @Resource
    private SysUserMapper sysUserMapper;

    @Override
    public Page<SysRole> page(Page<SysRole> page, SysRole sysRole) {
        LambdaQueryWrapper<SysRole> lqw = Wrappers.lambdaQuery(sysRole);
        return super.page(page, lqw);
    }

    @Override
    public List<TreeVO> listTree() {
        return super.list().stream().map(t -> new TreeVO(t.getId(),
                t.getName(), null)).toList();
    }

    @Override
    public List<SysRole> listAll() {
        return super.list();
    }

    @Override
    public boolean updateResourceSet(SysRoleDTO dto) {
        SysRole sysRole = dto.convert(SysRole.class);
        if (null == sysRole.getId()) {
            ApiAssert.fail(!super.save(sysRole), "角色信息保存失败");
        } else {
            ApiAssert.fail(!super.updateById(sysRole), "角色信息修改失败");
        }

        // 更新角色资源权限
        RoleResourceDTO rrd = new RoleResourceDTO();
        rrd.setRoleId(sysRole.getId());
        rrd.setResourceIds(dto.getResourceIds());
        return sysRoleResourceService.saveByRoleResourceParam(rrd);
    }

    @Override
    public boolean updateById(SysRole sysRole) {
        ApiAssert.isEmpty(sysRole.getId(), "主键不存在无法更新");
        return super.updateById(sysRole);
    }

    @Override
    public boolean updateStatusById(Long id, Integer status) {
        SysRole sysRole = new SysRole();
        sysRole.setId(id);
        sysRole.setStatus(Objects.equals(status, 1) ? 1 : 0);
        return super.updateById(sysRole);
    }

    @Override
    public boolean removeCheckByIds(List<Long> ids) {
        ids.forEach(id -> {
            ApiAssert.fail(sysUserRoleService.existRelByRoleId(id), "存在角色关联用户不允许删除");
            ApiAssert.fail(sysRoleResourceService.existRelByRoleId(id), "存在角色关联菜单权限不允许删除");
            ApiAssert.fail(rolePermissionMapper.existRelByRoleId(id) > 0, "存在角色关联权限不允许删除");
        });
        List<SysRole> sysRoles = this.listByIds(ids);
        ids = sysRoles.stream().filter(item -> !"admin".equals(item.getAlias())).map(SysRole::getId).collect(Collectors.toList());
        rolePermissionMapper.delete(Wrappers.<RolePermissionEntity>lambdaQuery()
                .in(RolePermissionEntity::getRoleId, ids));

        return super.removeByIds(ids);
    }

    @Override
    public IPage<PageRoleResponseVO> pageRole(IPage<PageRoleResponseVO> page, PageRoleVO pageRoleVO, List<Long> roleIdList) {
        List<PageRoleResponseVO> pageRoleResponseVOS = sysRoleMapper.pageRole(pageRoleVO, roleIdList);

        // 计算总记录数
        int total = pageRoleResponseVOS.size();
        // 设置总记录数
        page.setTotal(total);

        // 根据分页参数截取当前页数据
        int fromIndex = (int) ((page.getCurrent() - 1) * page.getSize());
        int toIndex = (int) Math.min(fromIndex + page.getSize(), total);

        // 处理分页边界情况
        if (fromIndex < total) {
            page.setRecords(pageRoleResponseVOS.subList(fromIndex, toIndex));
        } else {
            page.setRecords(java.util.Collections.emptyList());
        }

        return page;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateResourceSetNew(SysRoleDetailDTO dto) {
        SysRole sysRole = dto.convert(SysRole.class);
        if (null == sysRole.getId()) {
            ApiAssert.fail(!super.save(sysRole), "角色信息保存失败");
        } else {
            ApiAssert.fail(!super.updateById(sysRole), "角色信息修改失败");
        }

        // 更新角色资源权限
        RoleResourceDTO rrd = new RoleResourceDTO();
        rrd.setRoleId(sysRole.getId());
        rrd.setResourceIds(dto.getResourceIds());
        sysRoleResourceService.saveByRoleResourceParam(rrd);

        // 删除原有操作权限
        rolePermissionMapper.delete(Wrappers.<RolePermissionEntity>lambdaQuery().eq(RolePermissionEntity::getRoleId, sysRole.getId()));
        Map<String, Map<String, Object>> operate = dto.getOperatePermission();
        if (!Collections.isEmpty(operate)) {
            saveOperation(operate, sysRole);
        }
        // 更新角色数据权限
        List<SysRoleDetailDTO.DataPermission> dataPermissions = dto.getDataPermissions();
        if (!Collections.isEmpty(dataPermissions)) {
            saveDataPermission(dataPermissions, sysRole);
        }

        // 删除原有的用户关联
        sysUserRoleMapper.delete(Wrappers.<SysUserRole>lambdaQuery().eq(SysUserRole::getRoleId, sysRole.getId()));
        List<SysRoleDetailDTO.Member> members = dto.getMembers();
        // 保存新的关联
        if (!Collections.isEmpty(members)) {
            saveUserRole(members, sysRole);
        }

        return true;
    }

    /**
     * 获取角色详细信息
     * 包括：角色基本信息、菜单资源权限、操作权限、数据权限、成员配置等
     *
     * @param id 角色ID
     * @return 角色详细信息DTO
     */
    @Override
    public SysRoleDetailDTO getRoleDetail(Long id) {
        // 1. 参数校验
        if (null == id) {
            ApiAssert.fail("角色ID不存在");
        }
        SysRole role = this.getById(id);
        if (null == role) {
            ApiAssert.fail("角色不存在");
        }

        // 2. 创建返回值对象，复制角色基本信息
        SysRoleDetailDTO result = role.convert(SysRoleDetailDTO.class);

        // 3. 获取角色菜单资源权限
        List<Long> resourceIds = sysRoleResourceService.listByRoleId(id);
        result.setResourceIds(resourceIds);

        // 4. 获取角色操作权限配置
        List<RolePermissionEntity> rolePermissions = rolePermissionMapper.selectList(Wrappers.<RolePermissionEntity>lambdaQuery()
                .eq(RolePermissionEntity::getRoleId, id));
        // 构建操作权限映射：权限代码 -> 权限配置(scope + selectedIds)
        Map<String, Map<String, Object>> operatePermissionMap = rolePermissions.stream()
                .collect(Collectors.toMap(
                        RolePermissionEntity::getPermissionCode,
                        item -> {
                            Map<String, Object> operate = new HashMap<>();
                            String permissionValue = item.getPermissionValue();
                            String scope = item.getScope();
                            if ("all".equals(scope)) {
                                // 全部权限
                                operate.put("scope", "all");
                            } else {
                                // 部分权限，需要指定具体的选择项
                                operate.put("scope", scope);
                                operate.put("selectedIds", Arrays.asList(permissionValue.split(",")));
                            }
                            return operate;
                        }
                ));
        result.setOperatePermission(operatePermissionMap);

        // 5. 获取角色数据权限配置
        List<RoleDataIsolationEntity> roleDataIsolation = roleDataIsolationMapper.selectList(Wrappers.<RoleDataIsolationEntity>lambdaQuery()
                .eq(RoleDataIsolationEntity::getRoleId, id));
        // 转换数据权限实体为DTO对象
        List<SysRoleDetailDTO.DataPermission> dataPermissions = roleDataIsolation.stream().map(item -> {
            SysRoleDetailDTO.DataPermission dataPermission = new SysRoleDetailDTO.DataPermission();
            dataPermission.setId(item.getPermissionId());
            dataPermission.setName(item.getPermissionName());
            dataPermission.setType(item.getDataType());
            dataPermission.setScope(item.getContractScope());
            dataPermission.setStatus(item.getPermissionStatus());
            // 有效期类型转换：永久 or 固定期限
            dataPermission.setValidityType(item.getValidityType().equals(ValidityType.PERMANENT) ? "permanent" : "fixed");
            dataPermission.setStartDate(item.getValidityStartDate());
            dataPermission.setEndDate(item.getValidityEndDate());
            return dataPermission;
        }).collect(Collectors.toList());
        result.setDataPermissions(dataPermissions);

        // 获取角色成员配置
        List<SysUserRole> userRoles = sysUserRoleMapper.selectList(Wrappers.<SysUserRole>lambdaQuery()
                .eq(SysUserRole::getRoleId, id));
        List<Long> userIds = userRoles.stream().map(SysUserRole::getUserId).distinct().collect(Collectors.toList());
        
        // 1. 获取用户基本信息
        Map<Long, SysUser> userMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(userIds)) {
            userMap = sysUserMapper.selectList(Wrappers.<SysUser>lambdaQuery()
                            .in(SysUser::getId, userIds))
                    .stream().collect(Collectors.toMap(SysUser::getId, user -> user));
        }

        // 2. 获取用户实际所在部门关系（用于显示用户归属部门）
        List<SysUserDepartment> userDepartments = new ArrayList<>();
        if (!CollectionUtils.isEmpty(userIds)) {
            userDepartments = sysUserDepartmentMapper.selectList(Wrappers.<SysUserDepartment>lambdaQuery()
                    .in(SysUserDepartment::getUserId, userIds));
        }

        // 3. 收集所有相关的部门ID（包括用户实际部门和角色权限部门）
        Set<Long> allDepartmentIds = new HashSet<>();
        // 添加用户实际所在部门ID
        allDepartmentIds.addAll(userDepartments.stream()
                .map(SysUserDepartment::getDepartmentId)
                .collect(Collectors.toSet()));
        // 添加角色权限中配置的部门ID
        userRoles.stream()
                .filter(userRole -> userRole.getDepartmentAll() != null && !userRole.getDepartmentAll() && userRole.getDepartment() != null)
                .forEach(userRole -> {
                    String[] deptIds = userRole.getDepartment().split(",");
                    allDepartmentIds.addAll(Arrays.stream(deptIds)
                            .map(Long::valueOf)
                            .collect(Collectors.toSet()));
                });

        // 4. 批量查询所有部门信息，建立部门ID与名称的映射关系
        Map<Long, String> departmentMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(allDepartmentIds)) {
            departmentMap = sysDepartmentMapper.selectList(new LambdaQueryWrapper<SysDepartment>()
                            .in(SysDepartment::getId, allDepartmentIds))
                    .stream()
                    .filter(dept -> dept != null && dept.getId() != null)
                    .collect(Collectors.toMap(SysDepartment::getId, SysDepartment::getName));
        }

        // 5. 建立用户ID与实际所在部门的映射关系（用于设置deptName）
        Map<Long, List<SysUserDepartment>> userDeptMap = userDepartments.stream()
                .collect(Collectors.groupingBy(SysUserDepartment::getUserId));

        // 6. 构建成员信息结果
        final Map<Long, String> finalDepartmentMap = departmentMap;
        Map<Long, SysUser> finalUserMap = userMap;
        List<SysRoleDetailDTO.Member> members = userRoles.stream().map(item -> {
            SysUser user = finalUserMap.get(item.getUserId());
            // 如果用户不存在则跳过此用户
            if (null == user) {
                return null;
            }
            
            SysRoleDetailDTO.Member member = new SysRoleDetailDTO.Member();
            // 设置用户基本信息
            member.setUserId(user.getId());
            member.setName(user.getNickName());
            member.setEmployeeName(user.getRealName());
            member.setUserName(user.getUsername());
            member.setAvatar(user.getAvatar());

            // 设置部门权限配置（即使没有部门信息也要返回用户）
            member.setDepartmentAll(item.getDepartmentAll());
            List<Long> roleDepartmentIds = null;
            if (null != item.getDepartmentAll() && !item.getDepartmentAll() && item.getDepartment() != null) {
                // 解析角色权限中配置的部门ID列表
                roleDepartmentIds = Arrays.stream(item.getDepartment().split(","))
                        .map(Long::valueOf)
                        .collect(Collectors.toList());
                member.setDepartmentIds(roleDepartmentIds);

                // 设置角色权限部门对应的部门名称（departmentIds对应的部门名称）
                String roleDepartmentNames = roleDepartmentIds.stream()
                        .map(deptId -> finalDepartmentMap.getOrDefault(deptId, ""))
                        .filter(name -> !name.isEmpty())
                        .collect(Collectors.joining("、"));
                member.setDepartmentNames(roleDepartmentNames);
            }

            // 设置城市权限配置（即使没有城市信息也要返回用户）
            member.setCityAll(item.getCityAll());
            if (null != item.getCityAll() && !item.getCityAll() && item.getCity() != null) {
                member.setCities(Arrays.asList(item.getCity().split(",")));
            }

            // 设置用户实际所在部门名称（deptName - 用户归属部门显示）
            // 如果用户没有关联部门，deptName将为空字符串，但仍然返回该用户
            if (userDeptMap.containsKey(item.getUserId())) {
                String userActualDeptNames = userDeptMap.get(item.getUserId()).stream()
                        .map(userDepartment -> {
                            Long departmentId = userDepartment.getDepartmentId();
                            return finalDepartmentMap.getOrDefault(departmentId, "");
                        })
                        .filter(name -> !name.isEmpty())
                        .collect(Collectors.joining("、"));
                member.setDeptName(userActualDeptNames);
            } else {
                // 用户没有关联部门时，设置为空字符串
                member.setDeptName("");
            }

            return member;
        }).filter(Objects::nonNull).collect(Collectors.toList());

        result.setMembers(members);

        // 7. 返回完整的角色详细信息
        return result;
    }

    /**
     * 保存角色数据权限配置
     *
     * @param dataPermissions 数据权限列表
     * @param sysRole         角色对象
     */
    private void saveDataPermission(List<SysRoleDetailDTO.DataPermission> dataPermissions, SysRole sysRole) {
        List<String> permissionNames = dataPermissions.stream().map(SysRoleDetailDTO.DataPermission::getName).collect(Collectors.toList());
        Set<Long> permissionIds = dataPermissions.stream().filter(item -> item.getId() != null).map(SysRoleDetailDTO.DataPermission::getId).collect(Collectors.toSet());
        long count = roleDataIsolationMapper.selectCount(Wrappers.<RoleDataIsolationEntity>lambdaQuery()
                .in(RoleDataIsolationEntity::getPermissionName, permissionNames)
                .notIn(RoleDataIsolationEntity::getPermissionId, permissionIds));
        if (count > 0) {
            ApiAssert.fail("权限已存在");
        }
        List<RoleDataIsolationEntity> permissions = dataPermissions.stream().map(item -> {
            RoleDataIsolationEntity entity = new RoleDataIsolationEntity();
            if (item.getStartDate() != null && item.getEndDate() != null && item.getStartDate().after(item.getEndDate())) {
                ApiAssert.fail("开始时间不能大于结束时间");
            }
            entity.setPermissionId(item.getId());
            entity.setRoleId(sysRole.getId());
            entity.setPermissionName(item.getName());
            entity.setDataType(item.getType());
            entity.setContractScope(item.getScope());
            entity.setPermissionStatus(item.getStatus());
            entity.setValidityType("permanent".equals(item.getValidityType()) ? ValidityType.PERMANENT : ValidityType.FIXED_DATE);
            if (item.getStatus().equals(PermissionStatusType.ENABLE) && ValidityType.FIXED_DATE.equals(entity.getValidityType())) {
                entity.setValidityStartDate(item.getStartDate());
                entity.setValidityEndDate(item.getEndDate());
                if (item.getStartDate().after(new Date())) {
                    entity.setPermissionStatus(PermissionStatusType.UN_ENABLE);
                }
                if (item.getEndDate().before(new Date())) {
                    entity.setPermissionStatus(PermissionStatusType.EXPIRED);
                }
            }
            return entity;
        }).collect(Collectors.toList());
        roleDataIsolationMapper.insertOrUpdate(permissions);

    }

    /**
     * 保存角色操作权限配置
     *
     * @param operate 操作权限映射：权限代码 -> 权限配置
     * @param sysRole 角色对象
     */
    private void saveOperation(Map<String, Map<String, Object>> operate, SysRole sysRole) {
        Iterator<Map.Entry<String, Map<String, Object>>> iterator = operate.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Map<String, Object>> next = iterator.next();
            String key = next.getKey();
            Map<String, Object> value = next.getValue();
            RolePermissionEntity rolePermission = new RolePermissionEntity();
            rolePermission.setRoleId(sysRole.getId());
            rolePermission.setPermissionCode(key);
            String scope = (String) value.get("scope");
            rolePermission.setScope(scope);
            if (!"all".equals(scope)) {
                List<String> values = (List<String>) value.get("selectedIds");
                rolePermission.setPermissionValue(values.stream().collect(Collectors.joining(",")));
            }
            rolePermissionMapper.insert(rolePermission);
        }
    }

    /**
     * 保存角色成员配置（用户与角色的关联关系）
     *
     * @param members 成员列表
     * @param sysRole 角色对象
     */
    private void saveUserRole(List<SysRoleDetailDTO.Member> members, SysRole sysRole) {
        List<SysUserRole> userRoleList = members.stream().map(item -> {
            SysUserRole userRole = new SysUserRole();
            userRole.setRoleId(sysRole.getId());
            userRole.setUserId(item.getUserId());
            userRole.setDepartmentAll(item.getDepartmentAll());
            if (!item.getDepartmentAll()) {
                userRole.setDepartment(item.getDepartmentIds().stream().map(String::valueOf).collect(Collectors.joining(",")));
            }
            userRole.setCityAll(item.getCityAll());
            if (!item.getCityAll()) {
                userRole.setCity(String.join(",", item.getCities()));
            }
            return userRole;
        }).collect(Collectors.toList());
        sysUserRoleMapper.insert(userRoleList);
    }
}
